#include "player_widget.h"
#include "ui_player_widget.h"
#include <qpushbutton.h>
#include <iostream>
#include <QMetaObject>
#include <QMutex>
#include <QQueue>
#include "settings_widget.h"
#include "logger.h"
#include "d3d_helper.h"
#include "media_helper.h"
#include "d3d11_video_frame.h"
#include "helper.h"


PlayerWidget::PlayerWidget(QWidget* parent) :
    QWidget(parent),
    ui(new Ui::PlayerWidget)
{
    ui->setupUi(this);

    is_show_settings_ = false;
    settings_ = std::make_shared<SettingsWidget>();
    settings_->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); // 无边框可选

    bool ret = D3dHelper::create_d3d11_device(d3d11_device_, d3d11_context_);
    if (!ret)
    {
        APP_ERROR("init_soft: d3d11 device create failed.");
    }

    //ui->lineEdit->setText("C:\\Users\\Administrator\\Downloads\\Screenrecorder-2024-11-13-15-13-13-47.mp4");
    //ui->lineEdit->setText("C:\\Users\\Administrator\\Videos\\test\\1.mp4");
    ui->lineEdit->setText("C:\\Users\\Administrator\\Videos\\Bird_4K.mp4");
    connect(ui->btnOpen, &QPushButton::clicked, this, &PlayerWidget::slot_btn_open);
    connect(ui->btnClose, &QPushButton::clicked, this, &PlayerWidget::slot_btn_close);
    connect(ui->btnSettings, &QPushButton::clicked, this, &PlayerWidget::slot_btn_settings);
}

PlayerWidget::~PlayerWidget()
{
    delete ui;

    if (d3d11_device_)
    {
        d3d11_device_.Reset();
    }
    if (d3d11_context_)
    {
        d3d11_context_.Reset();
    }
}

void PlayerWidget::paintEvent(QPaintEvent* event)
{
}

void PlayerWidget::slot_btn_open()
{
    /* 媒体流 */
    stream_ = std::make_shared<FFmpegStream>();
    auto stream_params = std::make_shared<AVStreamParams>();
    stream_params->set_url(ui->lineEdit->text().toStdString().c_str());
    stream_->open(stream_params);

    switch (settings_->get_decode_type())
    {
        case SettingsWidget::SW_FFMPEG:
        {
            init_soft();
            break;
        }
        case SettingsWidget::HW_D3D11:
        {
            init_d3d();
            break;
        }
        case SettingsWidget::HW_DXVA:
        {
            init_dxva();
            break;
        }
        default:
            return;
    }

    is_stopped_ = false;   

    thread_ = std::make_shared<std::thread>([&]() {
        std::cout << "decoded thread: " << std::this_thread::get_id() << std::endl;
        int is_seek = true;

        while (!is_stopped_)
        {
            std::shared_ptr<AVPacket> pkt; 
            if (is_seek)
            {
                //stream_->seek(0.35);
                is_seek = false;
            }

            stream_->read_packet(pkt);

            if (pkt && stream_->is_video_packet(pkt))
            {
                Result err;
                std::shared_ptr<AVFrame> frame = FFmpegHelper::alloc_avframe();
                err = decoder_->send_packet(pkt);


                do{
                    err = decoder_->receive_frame(frame);
                    if (!err.is_success())
                        continue;

                    switch (settings_->get_decode_type())
                    {
                    case SettingsWidget::SW_FFMPEG:
                    {
                        render_soft_frame(frame);
                        break;
                    }
                    case SettingsWidget::HW_D3D11:
                    {
                        d3d_renderer_->render(frame.get());
                        break;
                    };
                    case SettingsWidget::HW_DXVA:
                    {
                        dxva_renderer_->render_frame(frame.get());
                        break;
                    };
                    };

                    Helper::Time::sleep_ms(1000 / stream_->get_video_frame_rate());

                } while (err.is_success() && err.code() != Result::ERR_EAGAIN_NEED_RETRY && err.code() != Result::ERR_END_OF_RECORD);
            }
        }
    });
}

void PlayerWidget::slot_btn_close()
{
    is_stopped_ = true;
    if (thread_ && thread_->joinable())
    {
        thread_->join();
        thread_.reset();
    }

    if (d3d_renderer_)
    {
        d3d_renderer_->uninitialize();
        d3d_renderer_.reset();
    }

    if (dxva_renderer_)
    {
        dxva_renderer_->uninitialize();
        dxva_renderer_.reset();
    }

    if (decoder_)
    {
        decoder_->close();
        decoder_.reset();
    }

    if (stream_)
    {
        stream_->close();
        stream_.reset();
    }

    recreate_window_widget();
}

void PlayerWidget::slot_btn_settings()
{
    is_show_settings_ = !is_show_settings_;
    if (is_show_settings_)
    {
        int width = this->width();
        int height = settings_->height();
        settings_->resize(width, height);


        QPoint global_pos = this->mapToGlobal(QPoint(0, 0));
        int x = global_pos.x();
        int y = global_pos.y() + this->height();
        settings_->move(x, y);

        settings_->show();
    }
    else
    {
        settings_->hide();
    }
}

void PlayerWidget::recreate_window_widget()
{
    /* d3d硬件切换 dxva 会黑屏，这里这个暂时解决这个问题 */

    if (ui->window) {
        ui->window->deleteLater();
    }

    QLabel* label = new QLabel(this);
    label->setObjectName("window");
    label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    label->setStyleSheet("background-color: black;");
    label->setAlignment(Qt::AlignCenter);

    ui->verticalLayout->addWidget(label);
    ui->window = label;
}

void PlayerWidget::init_soft()
{
    /* 普通解码器 */
    decoder_ = std::make_shared<FFmpegVideoDecoder>();
    auto decoder_params = std::make_shared<IVideoDecoderParams>();
    decoder_params->set_codec_params(stream_->get_video_codec_params());
    decoder_->open(decoder_params);
    auto codec_ctx = decoder_->get_codec_ctx();



    /* d3d渲染器 */
    d3d_renderer_ = std::make_shared<D3D11Renderer>();
    auto d3d_params = std::make_shared<D3D11RendererParams>();
    d3d_params->set_hwnd(HWND(ui->window->winId()));
    d3d_params->set_d3d11_device(d3d11_device_.Get());
    d3d_params->set_d3d11_device_context(d3d11_context_.Get());
    if (settings_->get_bt709())
    {
        d3d_params->set_enable_hdr2sdr(true);
    }
    d3d_renderer_->initialize(d3d_params);
}

void PlayerWidget::init_d3d()
{
    /* d3d解码器 */
    decoder_ = std::make_shared<FFmpegD3DVideoDecoder>();
    auto decoder_params = std::make_shared<FFmpegD3DVideoDecoderParams>();
    decoder_params->set_codec_params(stream_->get_video_codec_params());
    decoder_->open(decoder_params);
    auto codec_ctx = decoder_->get_codec_ctx();

    /* d3d渲染器 */
    d3d_renderer_ = std::make_shared<D3D11Renderer>();
    auto d3d_params = std::make_shared<D3D11RendererParams>();
    d3d_params->set_hwnd(HWND(ui->window->winId()));
    d3d_params->set_ffmpeg_codec_ctx(codec_ctx.get());
    if (settings_->get_bt709())
    {
        d3d_params->set_enable_hdr2sdr(true);
    }
    d3d_renderer_->initialize(d3d_params);
}

void PlayerWidget::init_dxva()
{
    /* dxva解码器 */
    decoder_ = std::make_shared<FFmpegDxvaVideoDecoder>();
    auto decoder_params = std::make_shared<FFmpegDxvaVideoDecoderParams>();
    decoder_params->set_codec_params(stream_->get_video_codec_params());
    decoder_params->set_hwnd(HWND(ui->window->winId()));
    decoder_->open(decoder_params);
    auto codec_ctx = decoder_->get_codec_ctx();

    /* dxva渲染器 */
    dxva_renderer_ = std::make_shared<DxvaRenderer>();
    auto dxva_params = std::make_shared<DxvaRendererParams>();
    dxva_params->set_hwnd(HWND(ui->window->winId()));
    dxva_params->set_ffmpeg_codec_ctx(codec_ctx.get());
    dxva_renderer_->initialize(dxva_params);
}

bool PlayerWidget::render_soft_frame(std::shared_ptr<AVFrame> frame)
{
    int width = frame->width;
    int height = frame->height;

    switch (frame->format)
    {
        case AV_PIX_FMT_YUV420P:
        {
            // 分配 ARGB 图像缓冲区（4 字节每像素）
            int stride_argb = width * 4;
            std::vector<uint8_t> argb_buffer(stride_argb * height);

            // 调用转换函数
            MediaHelper::yuv420p_to_rgb32_libyuv(
                frame->data[0], frame->linesize[0],  // Y
                frame->data[1], frame->linesize[1],  // U
                frame->data[2], frame->linesize[2],  // V
                argb_buffer.data(), stride_argb,      // ARGB 输出
                width, height,
                0 
            );

#if 1
            /* 上传到 D3D11 动态纹理 */
            Microsoft::WRL::ComPtr<ID3D11Texture2D> sw_texture;
            bool ret = D3dHelper::create_dynamic_texture2d(d3d11_device_.Get(), width, height, DXGI_FORMAT_B8G8R8A8_UNORM, sw_texture);
            if (!ret || !sw_texture)
            {
                APP_ERROR("create_dynamic_texture2d failed");
                return false;
            }

            D3D11_MAPPED_SUBRESOURCE mapped = {};
            HRESULT hr = d3d11_context_->Map(sw_texture.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
            if (SUCCEEDED(hr)) {
                for (int y = 0; y < height; ++y) {
                    memcpy((uint8_t*)mapped.pData + y * mapped.RowPitch,
                        argb_buffer.data() + y * stride_argb,
                        stride_argb);
                }
                d3d11_context_->Unmap(sw_texture.Get(), 0);
            }

            Microsoft::WRL::ComPtr<ID3D11Texture2D> hw_texture;
            ret = D3dHelper::copy_d3d11_software_to_hardware(d3d11_device_.Get(), d3d11_context_.Get(), sw_texture.Get(), hw_texture.GetAddressOf());
            if (!ret)
            {
                APP_ERROR("copy_d3d11_software_to_hardware failed");
                return false;
            }

            auto d3d_frame = std::make_shared<D3d11VideoFrame>();
            d3d_frame->set_context(d3d11_context_);
            d3d_frame->set_subresource_index(0);
            d3d_frame->set_texture(hw_texture);
            d3d_frame->set_width(width);
            d3d_frame->set_height(height);

            d3d_renderer_->render(d3d_frame);
#endif
             
#if 0
            QImage image(argb_buffer.data(), width, height, stride_argb, QImage::Format_ARGB32);
            QPixmap pixmap = QPixmap::fromImage(image).scaled(
                ui->window->size(),             // 目标大小
                Qt::IgnoreAspectRatio,         // 不保持宽高比
                Qt::SmoothTransformation       // 平滑缩放
            );
            ui->window->setPixmap(pixmap);
#endif
            break;
        }
        default:
        {
            APP_ERROR("unsupported pixel format: {}", frame->format);
            return false;
        }
    };

    return true;
}
